{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Horse-or-Human-WithAugmentation.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "metadata": {
        "colab_type": "code",
        "id": "RXZT2UsyIVe_",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "!wget --no-check-certificate \\\n",
        "    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/horse-or-human.zip \\\n",
        "    -O /tmp/horse-or-human.zip\n",
        "\n",
        "!wget --no-check-certificate \\\n",
        "    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/validation-horse-or-human.zip \\\n",
        "    -O /tmp/validation-horse-or-human.zip\n",
        "  \n",
        "import os\n",
        "import zipfile\n",
        "\n",
        "local_zip = '/tmp/horse-or-human.zip'\n",
        "zip_ref = zipfile.ZipFile(local_zip, 'r')\n",
        "zip_ref.extractall('/tmp/horse-or-human')\n",
        "local_zip = '/tmp/validation-horse-or-human.zip'\n",
        "zip_ref = zipfile.ZipFile(local_zip, 'r')\n",
        "zip_ref.extractall('/tmp/validation-horse-or-human')\n",
        "zip_ref.close()\n",
        "# Directory with our training horse pictures\n",
        "train_horse_dir = os.path.join('/tmp/horse-or-human/horses')\n",
        "\n",
        "# Directory with our training human pictures\n",
        "train_human_dir = os.path.join('/tmp/horse-or-human/humans')\n",
        "\n",
        "# Directory with our training horse pictures\n",
        "validation_horse_dir = os.path.join('/tmp/validation-horse-or-human/horses')\n",
        "\n",
        "# Directory with our training human pictures\n",
        "validation_human_dir = os.path.join('/tmp/validation-horse-or-human/humans')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "5oqBkNBJmtUv"
      },
      "cell_type": "markdown",
      "source": [
        "## Building a Small Model from Scratch\n",
        "\n",
        "But before we continue, let's start defining the model:\n",
        "\n",
        "Step 1 will be to import tensorflow."
      ]
    },
    {
      "metadata": {
        "id": "qvfZg3LQbD-5",
        "colab_type": "code",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "import tensorflow as tf"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "text",
        "id": "BnhYCP4tdqjC"
      },
      "cell_type": "markdown",
      "source": [
        "We then add convolutional layers as in the previous example, and flatten the final result to feed into the densely connected layers."
      ]
    },
    {
      "metadata": {
        "id": "gokG5HKpdtzm",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "Finally we add the densely connected layers. \n",
        "\n",
        "Note that because we are facing a two-class classification problem, i.e. a *binary classification problem*, we will end our network with a [*sigmoid* activation](https://wikipedia.org/wiki/Sigmoid_function), so that the output of our network will be a single scalar between 0 and 1, encoding the probability that the current image is class 1 (as opposed to class 0)."
      ]
    },
    {
      "metadata": {
        "id": "PixZ2s5QbYQ3",
        "colab_type": "code",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "model = tf.keras.models.Sequential([\n",
        "    # Note the input shape is the desired size of the image 300x300 with 3 bytes color\n",
        "    # This is the first convolution\n",
        "    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(300, 300, 3)),\n",
        "    tf.keras.layers.MaxPooling2D(2, 2),\n",
        "    # The second convolution\n",
        "    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),\n",
        "    tf.keras.layers.MaxPooling2D(2,2),\n",
        "    # The third convolution\n",
        "    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),\n",
        "    tf.keras.layers.MaxPooling2D(2,2),\n",
        "    # The fourth convolution\n",
        "    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),\n",
        "    tf.keras.layers.MaxPooling2D(2,2),\n",
        "    # The fifth convolution\n",
        "    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),\n",
        "    tf.keras.layers.MaxPooling2D(2,2),\n",
        "    # Flatten the results to feed into a DNN\n",
        "    tf.keras.layers.Flatten(),\n",
        "    # 512 neuron hidden layer\n",
        "    tf.keras.layers.Dense(512, activation='relu'),\n",
        "    # Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')\n",
        "    tf.keras.layers.Dense(1, activation='sigmoid')\n",
        "])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "8DHWhFP_uhq3",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "from tensorflow.keras.optimizers import RMSprop\n",
        "\n",
        "model.compile(loss='binary_crossentropy',\n",
        "              optimizer=RMSprop(lr=1e-4),\n",
        "              metrics=['acc'])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "ClebU9NJg99G",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "from tensorflow.keras.preprocessing.image import ImageDataGenerator\n",
        "\n",
        "# All images will be rescaled by 1./255\n",
        "train_datagen = ImageDataGenerator(\n",
        "      rescale=1./255,\n",
        "      rotation_range=40,\n",
        "      width_shift_range=0.2,\n",
        "      height_shift_range=0.2,\n",
        "      shear_range=0.2,\n",
        "      zoom_range=0.2,\n",
        "      horizontal_flip=True,\n",
        "      fill_mode='nearest')\n",
        "\n",
        "validation_datagen = ImageDataGenerator(rescale=1/255)\n",
        "\n",
        "# Flow training images in batches of 128 using train_datagen generator\n",
        "train_generator = train_datagen.flow_from_directory(\n",
        "        '/tmp/horse-or-human/',  # This is the source directory for training images\n",
        "        target_size=(300, 300),  # All images will be resized to 150x150\n",
        "        batch_size=128,\n",
        "        # Since we use binary_crossentropy loss, we need binary labels\n",
        "        class_mode='binary')\n",
        "\n",
        "# Flow training images in batches of 128 using train_datagen generator\n",
        "validation_generator = validation_datagen.flow_from_directory(\n",
        "        '/tmp/validation-horse-or-human/',  # This is the source directory for training images\n",
        "        target_size=(300, 300),  # All images will be resized to 150x150\n",
        "        batch_size=32,\n",
        "        # Since we use binary_crossentropy loss, we need binary labels\n",
        "        class_mode='binary')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "colab_type": "code",
        "id": "Fb1_lgobv81m",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "history = model.fit_generator(\n",
        "      train_generator,\n",
        "      steps_per_epoch=8,  \n",
        "      epochs=100,\n",
        "      verbose=1,\n",
        "      validation_data = validation_generator,\n",
        "      validation_steps=8)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "7zNPRWOVJdOH",
        "colab_type": "code",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "import matplotlib.pyplot as plt\n",
        "acc = history.history['acc']\n",
        "val_acc = history.history['val_acc']\n",
        "loss = history.history['loss']\n",
        "val_loss = history.history['val_loss']\n",
        "\n",
        "epochs = range(len(acc))\n",
        "\n",
        "plt.plot(epochs, acc, 'r', label='Training accuracy')\n",
        "plt.plot(epochs, val_acc, 'b', label='Validation accuracy')\n",
        "plt.title('Training and validation accuracy')\n",
        "\n",
        "plt.figure()\n",
        "\n",
        "plt.plot(epochs, loss, 'r', label='Training Loss')\n",
        "plt.plot(epochs, val_loss, 'b', label='Validation Loss')\n",
        "plt.title('Training and validation loss')\n",
        "plt.legend()\n",
        "\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}